package com.ztr.conversion.pdf2word;

import com.spire.doc.Document;
import com.spire.pdf.FileFormat;
import com.spire.pdf.PdfDocument;
import com.spire.pdf.widget.PdfPageCollection;
import lombok.extern.slf4j.Slf4j;

import java.io.File;

/**
 * <p>
 * Pdf 转 Word 工具类
 * </p>
 */
@Slf4j
public class Pdf2WordUtil {

    // 涉及到的路径
    // 1、pdf所在的路径，真实测试种是从外部引入的

    /**
     * 2、如果是大文件，需要进行切分，保存的子pdf路径
     */
    String splitPath = "./split/";

    /**
     * 3、如果是大文件，需要对子pdf文件一个一个进行转化
     */
    String docPath = "./doc/";

    /**
     * 将PDF文件转换为Word文档。
     *
     * @param srcPath PDF文件的源路径。
     * @param desPath 转换后Word文档的目标路径。
     */
    public void pdf2Word(String srcPath, String desPath) {
        // 初始化转换结果标志为false
        boolean result = false;
        try {
            // 检查源文件是否为PDF文件
            // 0、判断输入的是否是pdf文件
            // 第一步：判断输入的是否合法
            boolean flag = isPDFFile(srcPath);
            // 创建目标文件夹
            // 第二步：在输入的路径下新建文件夹
            boolean flag1 = create();

            // 如果源文件是PDF且目标文件夹创建成功
            if (flag && flag1) {
                // 加载PDF文档
                // 1、加载pdf
                PdfDocument pdf = new PdfDocument();
                pdf.loadFromFile(srcPath);
                PdfPageCollection num = pdf.getPages();

                // 如果PDF页数小于等于10页，直接转换为Word文档
                // 2、如果pdf的页数小于11，那么直接进行转化
                if (num.getCount() <= 10) {
                    pdf.saveToFile(desPath, FileFormat.DOCX);
                }
                // 如果PDF页数大于10页，分页转换为Word文档，并合并
                // 3、否则输入的页数比较多，就开始进行切分再转化
                else {
                    // 分页保存PDF
                    // 第一步：将其进行切分,每页一张pdf
                    pdf.split(splitPath + "test{0}.pdf", 0);

                    // 加载并转换每个分页PDF为Word，然后合并
                    // 第二步：将切分的pdf，一个一个进行转换
                    File[] fs = getSplitFiles(splitPath);
                    for (File f : fs) {
                        PdfDocument sonpdf = new PdfDocument();
                        sonpdf.loadFromFile(f.getAbsolutePath());
                        // 保留原文件名，改变后缀为.docx
                        sonpdf.saveToFile(docPath + f.getName().substring(0, f.getName().length() - 4) + ".docx",
                            FileFormat.DOCX);
                    }
                    // 合并转换后的Word文档
                    // 第三步：对转化的doc文档进行合并，合并成一个大的word
                    try {
                        result = this.merge(docPath, desPath);
                        log.debug(String.valueOf(result));
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            } else {
                log.debug("输入的不是pdf文件");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 如果转换成功，清除临时文件
            // 4、把刚刚缓存的split和doc删除
            if (result) {
                this.clearFiles(splitPath);
                this.clearFiles(docPath);
            }
        }
        log.debug("转换成功");
    }


    /**
     * 创建目录。
     * 该方法用于根据指定的路径创建两个目录：splitPath和docPath。
     * 如果这两个目录不存在，则分别尝试创建它们。
     *
     * @return 始终返回true，表示目录创建操作已执行（无论是否成功）。
     */
    private boolean create() {
        // 根据splitPath创建一个File对象，用于后续检查和创建该目录
        File f = new File(splitPath);
        // 根据docPath创建一个File对象，用于后续检查和创建该目录
        File f1 = new File(docPath);

        // 检查splitPath对应的目录是否存在，如果不存在，则尝试创建它
        if (!f.exists()) {
            f.mkdirs();
        }
        // 检查docPath对应的目录是否存在，如果不存在，则尝试创建它
        if (!f1.exists()) {
            f1.mkdirs();
        }

        // 目录创建操作完成后，始终返回true
        return true;
    }


    /**
     * 判断给定路径指向的文件是否为PDF文件。
     *
     * @param srcPath2 文件的路径。
     * @return 如果文件以“.pdf”结尾，则返回true；否则返回false。
     */
    private boolean isPDFFile(String srcPath2) {
        // 创建File对象，用于操作文件
        File file = new File(srcPath2);
        // 获取文件名
        String filename = file.getName();
        // 判断文件名是否以“.pdf”结尾
        if (filename.endsWith(".pdf")) {
            return true;
        }
        // 如果不是以“.pdf”结尾，则返回false
        return false;
    }


    /**
     * 获取指定路径下的所有PDF文件。
     *
     * 本方法用于遍历指定路径下的文件，筛选出所有PDF文件，并返回一个包含这些文件的数组。
     * 如果指定路径不存在或无法访问，则返回null。
     *
     * @param path 指定的文件路径。
     * @return 返回指定路径下所有PDF文件的数组，如果不存在PDF文件或路径不存在，则返回null。
     */
    private File[] getSplitFiles(String path) {
        // 创建一个File对象，表示指定的路径
        File f = new File(path);
        // 列出路径下的所有文件和目录
        File[] fs = f.listFiles();
        // 如果路径下没有文件或目录，则返回null
        if (fs == null) {
            return null;
        }
        // 返回路径下所有的文件和目录
        return fs;
    }


    /**
     * 清空指定工作空间根路径下的文件。
     * 该方法会删除工作空间根路径指向的文件或目录，如果存在的话。
     *
     * @param workspaceRootPath 工作空间根路径的字符串表示。这是要被清空的目录的路径。
     */
    public void clearFiles(String workspaceRootPath) {
        // 创建一个File对象，代表工作空间根路径
        File file = new File(workspaceRootPath);
        // 检查路径是否存在
        if (file.exists()) {
            // 如果存在，则调用deleteFile方法进行删除
            deleteFile(file);
        }
    }


    /**
     * 删除给定文件或目录。
     * 如果文件是目录，则递归删除目录中的所有文件和子目录。
     * 如果文件不是目录，则直接删除该文件。
     *
     * @param file 要删除的文件或目录。
     */
    public void deleteFile(File file) {
        // 如果文件是一个目录，则首先删除目录中的所有文件和子目录
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            if (files != null) {
                for (int i = 0; i < files.length; i++) {
                    deleteFile(files[i]);
                }
            }
        }
        // 删除文件或空目录
        file.delete();
    }


    /**
     * 合并多个DOCX文档。
     *
     * @param docPath 源文档目录路径，包含拆分的多个DOCX文档。
     * @param desPath 合并后文档的保存路径。
     * @return 返回true，表示合并操作成功。
     *
     * 此方法首先获取源目录中所有拆分的DOCX文档列表，然后利用Spire.Doc库将这些文档逐一插入到一个新的文档中，
     * 最后将合并后的文档保存到指定路径。此方法用于处理需要将多个DOCX文档合并为一个的情况。
     */
    private boolean merge(String docPath, String desPath) {
        // 获取源目录中所有拆分的DOCX文档
        File[] fs = this.getSplitFileList(docPath);
        // 打印源文档目录路径
        System.out.println(docPath);

        // 创建一个新的DOCX文档，用于合并其他文档
        Document document = new Document(docPath + "test0.docx");

        // 遍历拆分的DOCX文档列表，将每个文档插入到新的文档中
        for (int i = 1; i < fs.length; i++) {
            document.insertTextFromFile(docPath + "test" + i + ".docx", com.spire.doc.FileFormat.Docx_2013);
        }

        // 将合并后的文档保存到指定路径
        // 第四步：对合并的doc进行保存2
        document.saveToFile(desPath);
        return true;
    }



    /**
     * 获取指定路径下的所有文件列表。
     *
     * 本方法用于枚举指定路径下所有的文件和目录。如果路径不存在或者不是一个目录，则返回空数组。
     *
     * @param path 指定的文件路径字符串。
     * @return 返回一个File数组，包含指定路径下的所有文件和目录。如果路径不存在或者不是一个目录，则返回空数组。
     */
    private File[] getSplitFileList(String path) {
        // 创建一个File对象，代表指定的路径。
        File f = new File(path);
        // 列出指定路径下的所有文件和目录，返回一个File数组。
        return f.listFiles();
    }


}
